Auch als guter (!) Programmierer müssen Sie damit rechnen, dass Ihre Programme -
und seien sie noch so kurz - Fehler aufweisen. Einige davon sind einfacher Art -
Syntaxfehler, Endlosschleifen oder Beanstandungen (Option -w
). Andere hingegen
sind versteckt und liefern unverständliche oder gar keine Ergebnisse.
Ein Weg, herauszufinden, was sich an jeder Stelle in Ihrem Skript abspielt, führt über
print
-Anweisungen. Mit Hilfe von print
-Anweisungen können Sie die aktuellen
Werte der Variablen kontrollieren und feststellen, ob Schleifen und Bedingungen auch
ausgeführt werden. Es gibt jedoch noch einen anderen Weg, der besonders für
längere Skripts empfehlenswert ist. Perl verfügt über einen Quellcode-Debugger, mit
dem Sie die Ausführung eines Skripts schrittweise verfolgen und die verschiedenen
Werte der Variablen während der Ausführung des Skripts ausgeben lassen können.
Mit dem Debugger können Sie die Fehler in Ihrem Code schneller finden als mit
print
-Anweisungen.
In diesem Kapitel zeige ich Ihnen, wie Sie den Perl-Debugger einsetzen. Im einzelnen sehen Sie anhand eines kurzen Beispiels, wie Sie den Debugger normalerweise verwenden
Die Arbeitsweise des Perl-Debuggers läßt sich wahrscheinlich am besten anhand eines kleinen typischen Beispiels demonstrieren. Dazu gehen wir schrittweise durch die Ausführung eines einfachen Skripts mit Subroutinen, in diesem Falle das Namensskript aus Kapitel 6, »Bedingungen und Schleifen«, das eine Liste von Namen einliest, Sie bittet einen Suchbegriff einzugeben und die Namen zurückgibt, die dem Suchbegriff entsprechen.
Wenn Sie ein Skript bei eingeschaltetem Perl-Debugger ausführen, landen Sie direkt im Debugger und erhalten in etwa folgende Zeilen:
% perl -d statsfunk.pl statsdaten.txt
Loading DB routines from perl5db.pl version 1.01
Emacs support available.
Enter h or 'h h' for help.
main::(statsfunk.pl:3): &initvars();
DB<1>
Wenn Sie noch nicht wissen sollten, wie Sie den Debugger starten, zerbrechen Sie sich darüber nicht den Kopf. Ich werde gleich nach diesem kleinen Exkurs darauf eingehen.
Die Schlußzeile DB<1>
ist die Eingabeaufforderung des Debuggers. Hier geben Sie Ihre
Befehle ein. Die Zahl 1
besagt, dass dies der erste Befehl ist. Befehle lassen sich durch
Eingabe der Befehlsnummer wiederholen.
Die Zeile vor der Eingabeaufforderung gibt die aktuelle Codezeile an, die Perl anschließend ausführt. Der Teil zur Linken bezieht sich auf das aktuelle Paket, den Namen der Datei und die Zeilennummer. Der Teil zur Rechten ist die eigentliche Codezeile einschließlich der Kommentare zu der Zeile.
Um eine Codezeile auszuführen, können Sie den Befehl n
oder den Befehl s
verwenden. Der s
-Befehl geht etwas mehr in die Tiefe, da damit auch Subroutinen
ausgeführt werden. Mit dem n
-Befehl bleiben Sie bei der schrittweisen Ausführung auf
der obersten Ebene Ihres Skripts. Subroutinen werden im Hintergrund abgearbeitet.
Beide Befehle lassen sich wiederholen, indem man bei jeder Eingabeaufforderung die
Eingabe-taste betätigt:
main::(statsfunk.pl:3): &initvars();
DB<1> s
main::initvars(statsfunk.pl:8): $input = "";
DB<1>
main::initvars(statsfunk.pl:9): @nums = ();
DB<1>
main::initvars(statsfunk.pl:10): %freq = ();
DB<1>
In diesem Beispiel fällt auf, dass, sobald die Ausführung des Skripts in die
&initvars()
-Subroutine verzweigt (erfolgt in unserem Beispiel gleich in der ersten
Zeile), die Informationen auf der linken Seite der Ausgabe den Namen dieser
Subroutine widerspiegeln. So wissen Sie jederzeit, wo im Skript Sie sich befinden.
Falls Sie aber die Übersicht verloren haben oder anhand der einzelnen Zeile Ihre
Position im Skript nicht festlegen können, ist es möglich mit Hilfe des Befehls l
(steht
für list) weitere Codezeilen anzeigen zu lassen:
DB<1> l
10==> %freq = (); # Hash: Zahl-Haeufigkeit
11: $maxfreq = 0; # hoechste Haeufigkeit
12: $count = 0; # Anzahl Zahlen
13: $sum = 0; # Summe
14: $avg = 0; # Durchschnitt
15: $med = 0; # Median
16: @keys = (); # temp keys
17: $totalspace = 0; # gesamte Breite des Histogramms
18 }
19
Mit l
lassen sich die auf die aktuelle Zeile folgenden zehn Zeilen am Bildschirm
ausgeben. Durch Eingabe eines Minuszeichens können Sie auch die zehn Zeilen vor
der aktuellen Zeile sichtbar machen. Durch mehrmaliges Eingeben von l
und -
können Sie sich den Quellcode auflisten lassen, die folgenden Zeilen und
zurückliegende. Beachten Sie jedoch, dass Sie damit lediglich die Zeilen anzeigen
lassen und Ihre Codezeile im Kontext sehen können - der Code selbst wird damit
nicht ausgeführt.
Beim Durchschreiten des Codes können Sie die Werte aller Variablen - Skalare,
Arrays, Hashes und so weiter - mit dem Befehl x
ausgeben lassen. Im nächsten
Beispiel hat die Subroutine &getinput()
gerade eine Zeile aus der Eingabedatei
eingelesen, diese Zeile in der Variablen $input
abgelegt und anschließend das Zeichen
für »Neue Zeile« aus dieser Zeile entfernt. Bei DB<5>
wird der Wert von $index
und die
aktuellen Werte von @nums
ausgegeben (die Array-Indizes stehen links und die
eigentlichen Elemente rechts). Beachten Sie, dass die Codezeile (hier Zeile 23)
angezeigt wird, bevor sie ausgeführt wird, so dass der Wert von $input
noch nicht in
@nums
abgelegt ist.
main::getinput(statsfunk.pl:21): while (defined ($input = <>)) {
DB<5> s
main::getinput(statsfunk.pl:22): chomp ($input);
DB<5>
main::getinput(statsfunk.pl:23): $nums[$count] = $input;
DB<5> x input
0 5
DB<6> x @nums
0 1
1 4
2 3
3 4
DB<7>
Mit dem x
-Befehl können Sie auch, wie im folgenden Beispiel zu sehen, Perl-Code
ausführen, um die Anzahl der Elemente in @raw
zu ermitteln oder das erste Element
anzuzeigen:
DB<3> x scalar(@nums)
0 4
DB<4> x $raw[0]
0 1
Wenn Sie Ihr Skript mit s
oder n
debuggen, wird Ihnen jede Zeile bis ins kleinste
Detail angezeigt - manchmal sogar ausführlicher, als Sie es benötigen. Innerhalb einer
Subroutine können Sie mit dem Befehl r
das schrittweise Debuggen der Subroutine
aufheben, den Rest der Subroutine ausführen und dann dorthin zurückkehren, von wo
die Subroutine aufgerufen wurde. Dies kann bei verschachtelten Subroutinen
wiederum eine Subroutine sein.
Sie können mit der Eingabe von c
den Debug-Prozess jederzeit abbrechen.
Anschließend führt Perl den Rest des Skripts ohne weitere Unterbrechungen aus (es
sei denn, Sie haben explizit Haltepunkte in Ihrem Skript aufgenommen, um zum
Beispiel eine Eingabe einzulesen.)
Zusätzlich zu der Möglichkeit, die Ausführung Ihres Skripts zeilenweise zu verfolgen,
können Sie die Ausführung mit Haltepunkten steuern. Unter einem Haltepunkt
versteht man eine Markierung in einer Codezeile oder zu Beginn einer Subroutine. Mit
dem Befehl c
wird das Skript bis zu einem gesetzten Haltepunkt ausgeführt und dort
unterbrochen. Am Haltepunkt können Sie dann mit n
oder s
den Code zeilenweise
durchgehen, mit x
die Variablen ausgeben oder mit c
den nächsten Haltepunkt
ansteuern.
Betrachten wir beispielsweise das Skript statsmenue.p1, mit dem wir gestern das
stats-Skript in mehrere Subroutinen unterteilt haben. Die Subroutine &countsum()
gibt die Anzahl und die Summe der Daten aus. Um die Summe zu berechnen, ruft sie
die Subroutine &sumnums()
auf. Sie setzen einen Haltepunkt bei der Subroutine
&sumnums()
, indem Sie den Befehl b
gefolgt von dem Namen der Subroutine
eingeben. Dann führen Sie mit c
das Skript bis zu diesem Haltepunkt aus.
# perl -d statsmenue.pl statsdaten.txt
Loading DB routines from perl5db.pl version 1.01
Emacs support available.
Enter h or 'h h' for help.
main::(statsmenue.pl:3): @nums = (); # array of numbers;
DB<1> b sumnums
DB<2> c
Was moechten Sie ausgeben? (Beenden mit Q):
1. eine Liste der Zahlen
2. die Anzahl und Summe der Zahlen
3. die kleinste und die groesste Zahl
4. den Durchschnitts- und den Medianwert
5. ein Diagramm, wie oft jede Zahl vorkommt
Ihre Auswahl --> 2
Anzahl der Zahlen: 70
main::sumnums (statsmenue.pl:72): my $sum = 0;
DB<2>
Und wie, meinen Sie, sollen Sie sich die Namen all Ihrer Subroutinen merken? Kein
Problem. Mit der Eingabe von S
können Sie alle verfügbaren Subroutinen ausgeben
lassen. Insbesondere S main
wird die von Ihnen definierten Subroutinen anzeigen
(wundern Sie sich jedoch nicht, wenn auch hier einige zusätzliche Perl-Routinen
auftauchen). Betrachten Sie das folgende Beispiel:
DB<7> S main
main::BEGIN
main::countsum
main::getinput
main::maxmin
main::meanmed
main::printdata
main::printhist
main::printmenu
main::sumnums
DB<8>
Der
main
-Teil heißt so in Anlehnung an dasmain
-Paket, in dem sich all Ihre Variablen und Subroutinen standardmäßig befinden. Auf Pakete werden wir im folgenden Kapitel 13 noch näher eingehen.
Wenn Sie einen Haltepunkt in einer bestimmten Zeile setzen wollen, können Sie mit l
das Skript listenförmig ausgeben, um die Zeile zu ermitteln, und dann diese
Zeilennummer zusammen mit dem Befehl b
verwenden:
DB<3> l
43: print "5. ein Diagramm, wie oft jede Zahl vorkommt.\n";
44: while () {
45: print "\nIhre Auswahl --> ";
46: chomp($in = <STDIN>);
47: if ($in =~ /^\d$/ || $in =~ /^q$/i) {
48: return $in;
49 } else {
50: print "Ungueltige Eingabe. 1-5 oder Q, bitte.\n";
51 }
DB<3>
Beachtenswert ist auch, dass der Debugger die Ausführung des Skripts zur Laufzeit
verfolgen kann. Mit den Befehlen n
und s
können Sie zwar jede Anweisung einzeln
ausführen lassen, aber manchmal möchte man die Zeilen nicht einzeln durchgehen,
sondern sich trotzdem die einzelnen Anweisungen bei der Ausführung ausgeben
lassen. Der Befehl t
schaltet die Verfolgung ein und aus. Wir verfolgen hier die
Subroutine &printdata()
, wobei ein Haltepunkt an die Spitze der foreach
-Schleife
gesetzt wurde:
DB<1> b 59
DB<2> t
Trace = on
DB<2> c
Was moechten Sie ausgeben? (Beenden mit Q):
1. eine Liste der Zahlen
2. die Anzahl und Summe der Zahlen
3. die kleinste und die groesste Zahl
4. den Durchschnitts- und den Medianwert
5. ein Diagramm, wie oft jede Zahl vorkommt
Ihre Auswahl --> 1
die Zahlen:
1 main::printdata(statsmenue.pl:59): foreach $num (@nums) {
DB<2> c
main::printdata(statsmenue.pl:60): print "$num ";
1 main::printdata(statsmenue.pl:61): if ($i == 10) {
main::printdata(statsmenue.pl:64): } else { $i++; }
main::printdata(statsmenue.pl:59): foreach $num (@nums) {
DB<2>
An diesem Beispiel möchte ich Ihnen zeigen, dass bei der Verfolgung nicht nur die
Ausgabe des Skripts angezeigt (man beachte die 1
am Zeilenanfang in der Mitte der
Ausgabe direkt nach dem Befehl c
), sondern auch jede Skriptzeile ausgegeben wird.
Würden wir hier erneut c
eingeben, würde die foreach
-Schleife erneut durchlaufen,
und wir erhielten die gleiche Ausgabe.
Verlassen wird der Debugger mit q
(einfach nur q
).
DB<18> q
%
Soweit - so gut. Nach diesem Exkurs sollten Sie eine ungefähre Vorstellung davon haben, wie der Debugger funktioniert. Der Rest dieses Kapitels ist den Details der spezielleren Befehle gewidmet.
Der für Perl mitgelieferte Debugger wird von der Befehlszeile aus mit der Option -d
gestartet. Während Sie Ihre Perl-Skript unter Unix oder Windows NT lediglich durch
Angabe des Skriptnamens aufgerufen haben, so müssen Sie zum Debuggen Perl
explizit aufrufen, gefolgt von dem Skriptnamen und den Argumenten. Wenn Sie also
normalerweise ein Skript wie folgt aufrufen:
% meinSkript.pl namen.txt
lautet der Aufruf für den Debugger wie folgt:
% perl -d meinSkript.pl namen.txt
Wenn Sie der Meinung sind, dass Sie den Debugger recht häufig für ein bestimmtes
ziemlich schwieriges Skript einsetzen werden, können Sie alternativ die Option -d
auch in der shebang-Zeile des Skripts aufnehmen.
#!/usr/bin/perl -wd
Vergessen Sie nicht, die Option wieder zu entfernen, sobald Sie mit dem Debuggen fertig sind.
Um den Debugger in MacPerl einzuschalten, wählen Sie im Script-Menü den Befehl Perl Debugger, speichern Sie Ihr Skript, und führen Sie es dann wie gewohnt aus. Wenn Sie vorhaben, Ihr Skript als Droplet zu verwenden (das Dateien als Eingabe akzeptiert), dann vergessen Sie nicht das Skript als Droplet zu speichern.
Beachten Sie, dass vor Aufruf Ihres Debuggers das Skript frei von Syntaxfehlern und Warnungen sein muss. Sie müssen diese fatalen Fehler beseitigen, bevor Sie Ihr Skript debuggen können. Da diese Aufgabe Ihnen ohnehin nicht erspart bliebe, sollte die Bürde nicht zu schwer sein.
Während der Debugger läuft, können Sie jederzeit mit dem Befehl h
Hilfe anfordern.
Damit wird eine Liste der möglichen Befehle ausgegeben. Rollt Ihnen der Bildschirm
zu schnell, steht Ihnen der Befehl |h
zur Verfügung (pausiert nach jeder Seite). Hilfe
gibt es auch zu jedem einzelnen Befehl (h
plus Argument). Alle Befehle, die dem
Argument entsprechen, werden dann wie folgt ausgegeben:
DB<3> h c
c [line|sub] Continue; optionally inserts a one-time-only breakpoint
at the specified position.
command Execute as a perl statement in current package.
DB<4>
Jeder Debugger-Befehl hat eine bestimmte Nummer (im obigen Beispiel hatte der
Befehl h
c
die Nummer 3). Mit einem Ausrufezeichen und der Befehlsnummer können
Sie jederzeit auf einen der vorangegangenen Befehle Bezug nehmen.
DB<4> !3
Einen Überblick über die letzten paar Befehle erhalten Sie mit H
und einer Zahl, der
ein Minuszeichen vorangestellt wurde:
DB<13> H -3
13: H-3
12: b sumnums
11: x @nums
DB<14>
Sie verlassen den Debugger mit q
. Ist die Ausführung Ihres Perl-Skripts abgeschlossen,
können Sie mit R
die Ausführung erneut starten. Beachten Sie, dass R
je nach
Umgebung und Befehlszeilenargumenten, die für das Skript verwendet wurden, nicht
funktioniert.
Verfolgen bedeutet, dass Sie jede Zeile Ihres Skripts angezeigt bekommen, während sie von Perl ausgeführt wird. Wird eine Zeile dabei mehrmals hintereinander ausgeführt, wie zum Beispiel in einer Schleife, wird jeder Durchgang von Perl angezeigt. Bei sehr komplexen Skripten ist die Ausgabe deshalb oft umfangreicher als notwendig. Aber mit Haltepunkten an bestimmten Positionen mag es zeitweise recht nützlich sein, die genaue Reihenfolge der Ausführung des Skripts zu verfolgen.
Um zwischen den Verfolgungsmodi in Ihrem Perl-Skript hin- und herzuschalten, steht
Ihnen t
zur Verfügung. Ist die Verfolgung ausgeschaltet, wird sie mit t
eingeschaltet
und umgekehrt. Die folgende Ausgabe zeigt zum Beispiel das Ergebnis einer
ausgeführten Schleife mit ausgeschalteter und mit eingeschalteter Verfolgung (der
Haltepunkt befindet sich in Zeile 59, einer foreach
-Schleife).
main::printdata(statsmenue.pl:59): foreach $num (@nums) {
DB<4> c
2 main::printdata(statsmenue.pl:59): foreach $num (@nums) {
DB<4> t
Trace = on
DB<4> c
main::printdata(statsmenue.pl:60): print "$num ";
2 main::printdata(statsmenue.pl:61): if ($i == 10) {
main::printdata(statsmenue.pl:64): } else { $i++; }
main::printdata(statsmenue.pl:59): foreach $num (@nums) {
Bei eingeschalteter Verfolgung können Sie die Ausführung Ihres Skripts mitverfolgen.
Eine Stapelverfolgung zeigt Ihnen, wo Sie bereits gewesen sind - im Falle von
verschachtelten Subroutinen zeigt sie Ihnen die Subroutine, die die von Ihnen zur Zeit
ausgeführte Subroutine aufgerufen hat, und alle, die eventuell noch darüber
angeordnet sind - bis zur obersten Ebene Ihres Skripts. Die Stapelverfolgung wird mit
dem Befehl T
aktiviert:
DB<4> T
@ = main::sumnums() called from file 'statsmenue.pl' line 68
$ = main::countsum() called from file 'statsmenue.pl' line 13
DB<4>
Die Zeichen zu Beginn dieser Zeilen geben den Kontext an, in dem die Subroutine
aufgerufen wurde. So zeigt die erste Zeile dieser Stapelverfolgung, dass die Subroutine
&sumnums()
(die aktuelle Routine) in einem Listenkontext (angezeigt durch das @
-
Zeichen am Zeilenanfang) von der Routine &countsum()
aus aufgerufen wurde. Die
Routine &countsum()
wiederum wurde von dem main
-Teil des Skripts in einem
skalaren Kontext aufgerufen (angezeigt durch das $
am Zeilenanfang).
Um den Code Ihres Skripts schrittweise zu durchwandern, müssen Sie einen der
Befehle s
oder n
verwenden. Mit der Eingabetaste wiederholen Sie Ihre vorige
Eingabe (s
oder n
). Bei jedem Schritt zeigt Perl die Codezeile an, die es als nächstes
ausführen wird (nicht die aktuell ausgeführte Codezeile):
DB<1> s
main::getinput(statsmenue.pl:29): $nums[$count] = $_;
DB<1>
Der Unterschied zwischen s
und n
liegt darin, dass der Befehl s
bei der Überwachung
in die Ausführung untergeordneter Subroutinen verzweigt, während n
diese
Subroutinen zwar ausführt, jedoch bei der schrittweisen Überwachung auf der
gleichen Ebene bleibt.
Um die Ausführung einer Subroutine in Einzelschritten abzubrechen, den Rest der
aktuellen Subroutine auszuführen und zu der Anweisung zurückzukehren, die die
Subroutine ursprünglich aufgerufen hat, verwenden Sie den Befehl r
.
Um die Einzelschrittausführung für den gesamten Code aufzuheben, verwenden Sie
den Befehl c
.
Sie können den aktuell ausgeführten Quelltext mit Zeilennummern ausgeben lassen, um sich den Kontext zu der aktuellen Codezeile anzeigen zu lassen oder um nach einer speziellen Zeile zu suchen, bei der ein Haltepunkt gesetzt werden soll.
Die nächsten zehn Zeilen des Codes erscheinen bei Eingabe des Befehls l
:
DB<15> l
79==> $sum += $num;
80 }
81: return $sum;
82 }
83
84 # kleinste und groesste Zahl ausgeben
85 sub maxmin {
86: print "Kleinste Zahl: $nums[0]\n";
87: print "Groesste Zahl: $nums[$#nums]\n\n";
88 }
DB<15>
Weitere Aufrufe von l
werden die jeweils folgenden zehn Zeilen anzeigen. Sie können
l
aber auch zusammen mit einer Zeilennummer verwenden, um genau diese Zeile
anzuzeigen, oder mit einem Zeilenbereich (zum Beispiel 1-4
), um speziell diese Zeilen
auszugeben, oder mit dem Namen einer Subroutine, um die ersten zehn Zeilen dieser
Subroutine aufzulisten.
Um in der Anzeige einige Zeilen zurückzuwandern, gibt es den Befehl -. Wie schon bei
dem Befehl l
können Sie mit mehrmaliger Eingabe von -
auch weiter
zurückwandern.
Mit dem Befehl w
erhalten Sie einen Ausschnitt um die aktuelle Zeile (oder die
spezifizierte Zeile, falls angegeben): Es werden einige Zeilen davor und einige Zeilen
danach eingeblendet. Ein Pfeil (==>
) markiert die aktuelle Zeilenposition:
DB<3> w
24 # Input aus Datei lesen und dann sortieren
25 sub getinput {
26: my $count = 0;
27==> while (<>) {
28: chomp;
29: $nums[$count] = $_;
30: $count++;
31: }
32: @nums = sort { $a <=> $b } @nums;
33: }
Mit einem Mustervergleich suchen Sie nach einer bestimmten Zeile im Quelltext. /
daten/
wird zum Beispiel nach dem ersten Vorkommen des Wortes daten
suchen.
Mit ?muster?
durchsuchen Sie die Datei rückwärts.
Einen letzten nützlichen Befehl zum Auflisten möchte ich Ihnen noch vorstellen: S
.
Damit werden Ihnen alle Subroutinen, die im Skript auftauchen, angezeigt. Die
meisten dieser Subroutinen sind Perl- oder Debugger-spezifisch. S
zusammen mit
einem Paketnamen (zum Beispiel main
) wird jedoch nur die Subroutinen in dem Paket
ausgeben:
DB<20> S main
main::BEGIN
main::get_muster
main::namen_lesen
main::suche_muster
Morgen werde ich Ihnen mehr zu den Paketen erzählen.
In dem Quelltext zu Ihrem Skript herumzublättern ist nicht nur schön und praktisch, es hilft Ihnen auch, herauszufinden, was in Perl abläuft, wenn Ihr Skript ausgeführt wird. Die folgenden Befehle dienen dazu, die Werte der Variablen auszugeben:
X
gibt alle Variablen in dem aktuellen Paket aus. Da viele dieser Variablen Perl-
spezifisch sind (einschließlich spezieller Variablen wie @_
, $_
und $1
), kann die Liste
ziemlich lang werden. X
zusammen mit dem Namen einer Variablen gibt alle Variablen
aus, die mit dem Suchnamen übereinstimmen. Beachten Sie, dass Sie nur den Namen
selbst angeben und nicht die Präfixe wie $
, @
oder %
. X foo
gibt die Werte aller
Variablen aus, deren Namen foo
lautet ($foo
, @foo
und %foo
).
Der Befehl V
wird verwendet wie X
. Zusätzlich kann jedoch ein optionaler Paketname
angegeben werden, um die Variablen dieses Pakets auszugeben. Diese Eigenschaft ist
allerdings erst von Belang, wenn Sie mit Paketen arbeiten. Der Vollständigkeit halber
möchte ich Sie hier jedoch erwähnen.
Der Befehl X
birgt das Problem, dass lokale Variablen innerhalb von Subroutinen
offensichtlich nicht erkannt werden. Um die Werte von lokalen Variablen auszugeben
oder kleinere Perl-Fragmente auszuführen, an deren Ergebnis Sie interessiert sind,
verwenden Sie den x
-Befehl:
DB<3> x $input
0 'Dante Alighieri'
Wenn Sie Arrays oder Hashes ausgeben, wird der Inhalt des Arrays oder des Hash
angezeigt. Die Ausgabe von X
und V
ist etwas einfacher zu lesen als die von x
,
besonders im Falle von Hashes. Und so sieht ein Hash bei der Verwendung von X
aus:
DB<4> X %names
%names = (
'Adams' => 'Douglas'
'Alexander' => 'Lloyd'
'Alighieri' => 'Dante'
'Asimov' => 'Isaac'
'Barker' => 'Clive'
'Bradbury' => 'Ray'
'Bronte' => 'Emily'
)
Das Setzen von Haltepunkten innerhalb eines Skripts erlaubt es Ihnen, das Skript
normal auszuführen und an bestimmten Punkten (in der Regel dort, wo alles anfängt,
falsch zu laufen) anzuhalten. Sie können beliebig viele Haltepunkte in Ihrem Skript
setzen und dann mit den Befehlen zur Einzelschrittausführung oder zur
Variablenausgabe das Problem einkreisen. Nehmen Sie mit c
die Ausführung des
Codes nach dem Haltepunkt wieder auf.
Sie setzen einen Haltepunkt mit dem Befehl b
. Wird der Befehl ergänzt um den
Namen einer Subroutine, befindet sich der Haltepunkt an der ersten Anweisung
innerhalb dieser Subroutine. Der Befehl b
zusammen mit einer Zeilennummer setzt
den Haltepunkt in genau dieser Zeile. Ohne Argumente wird mit b
ein Haltepunkt in
der aktuellen Zeile gesetzt. Im Quellcode-Listing erscheinen Haltepunkte als ein
kleingeschriebenes b
(in unserem Beispiel in Zeile 33):
DB<19> w 33
30 }
31
32 sub suche_muster {
33:b my $key = $_[0];
34: my $gefunden = 0;
35: foreach $ln (sort keys %namen) {
36==> if ($ln =~ /$key/o || $namen{$ln} =~ /$key/o) {
37: print "$ln, $namen{$ln}\n";
38: $gefunden = 1;
39 }
Der Befehl L
dient dazu, alle Haltepunkte, die Sie gesetzt haben, auf einmal
auszugeben:
DB<22> L
namessub.pl:
9: my @raw = (); # raw Liste von Namen
break if (1)
33: my $key = $_[0];
break if (1)
Gelöscht wird ein Haltepunkt, indem die Zeilennummer oder der Subroutinenname
zusammen mit dem Befehl d
verwendet wird. Mit D
werden alle gesetzten Haltepunkte
auf einmal gelöscht.
DB<22> d 9
DB<23> L
namessub.pl:
33: my $key = $_[0];
break if (1)
Bis jetzt habe ich Ihnen vornehmlich die Befehle vorgestellt, die Ihnen den Einstieg in
die Arbeit mit dem Debugger erleichtern und die Sie wahrscheinlich am häufigsten
anwenden. Neben den hier vorgestellten Befehlen können Sie mit Perl aber auch
noch bedingte Haltepunkte setzen, den Wert der Variablen ändern, Aktionen in
bestimmten Zeilen ausführen und mehr oder weniger komplette Perl-Skripts eingeben
und deren Ausführung interaktiv verfolgen. Sobald Sie mit dem Perl-Debugger etwas
vertrauter sind, werden Sie den Befehl h
garantiert öfter verwenden und, wenn nötig,
die perldebug-Manpage zu Rate ziehen.
Der Debugger wird Ihnen helfen, Probleme in Ihrem Code zu lokalisieren. Die fleißige
Verwendung der Option -w
ermöglicht es, viele Probleme zu verhindern, bevor das
Skript überhaupt gestartet wird (oder bevor man den Debugger überhaupt
konsultieren muss, um herauszufinden, was falsch läuft). Machen Sie es sich also zur
Gewohnheit, wann immer möglich, -w
zu verwenden.
In diesem Kapitel habe ich Ihnen die wichtigsten Debugger-Befehle vorgestellt. Wenn Sie so richtig in die Arbeit mit dem Debugger einsteigen, sollten Sie in der perldebug- Manpage oder der Online-Hilfe nachschauen, welche weiteren Befehle und Optionen Ihnen zur Verfügung stehen.
In Perl können Sie das Verhalten des Debuggers anpassen. Sie können aber auch ein
ganz anderes Debugger-System verwenden. Der Schalter -d
zusammen mit einem
Doppelpunkt und dem Namen des Moduls bindet das Modul als neuen Debugger ein.
So können Sie zum Beispiel mit dem Modul Devel::DProf
von CPAN Laufzeitprofile
Ihrer Perl-Skripten erstellen (testen, wie lange Ihre Subroutinen dauern, um
herauszufinden, wo Ihr Code noch effizienter sein könnte). Sobald Sie das Modul
installiert haben, können Sie es wie folgt aufrufen:
% perl -d:DProf dasSkript.pl
Die Datei perl5db.pl
enthält den Code für den Debugger. Sie können diese Datei
kopieren und Ihren Ansprüchen gemäß modifizieren. Weitere Informationen finden
Sie in der perldebug-Manpage oder den Dokumentationen zu dem DProf
-Modul.
Sie können den Debugger nutzen, um Perl in einer Art interaktivem Modus auszuführen. So können Sie Befehle testen und deren Ausgabe direkt verfolgen. Sie benötigen dafür nicht einmal ein richtiges Skript. Und so sieht ein einfacher Befehl aus, mit dem Sie den Debugger ohne ein Skript zum Debuggen laden:
% perl -d -e1
Um genau zu sein, Sie haben Perl damit ein Skript zur Ausführung übergeben. Dieses Skript ist jedoch nur ein Zeichen lang:
1
. Mit der Option-e
werden Perl-Skripts direkt von der Befehlszeile ausgeführt. Dieses Thema schneiden wir noch einmal am Ende des Buches in Kapitel 20 an.
In den letzten zwei Wochen habe ich mich bemüht, Sie auf häufige Fehler hinzuweisen, die fast allen Perl-Anfängern (und auch erfahrenen Programmierern) immer wieder unterlaufen. In der perltraps-Manpage finden Sie ebenfalls eine Liste der häufigsten Fallen und darüber hinaus noch vieles mehr. Schon ein kurzes Studieren dieser Seite wird Ihnen viele interessante Hinweise liefern, wenn es darum geht, Probleme bei schwierigem Code zu lösen.
Die Perl-Dokumentation umfaßt außerdem einen umfangreichen Satz an FAQ- Dateien (häufig gestellte Fragen). Bevor Sie sich vor Verzweiflung über ein bestimmtes Problem die Haare raufen, sehen Sie lieber einmal in den FAQs nach. Beginnen Sie dabei mit der perlfaq-Manpage, und lassen Sie sich von dort aus leiten.
Heute haben wir zwar nicht besonders viel über Perl selbst erfahren, dafür aber um so mehr über den dazugehörigen Befehlszeilen-Debugger. Sie wissen jetzt, wie Sie den Debugger aufrufen und starten, wie Sie jede Zeile Ihres Skripts einzeln ausführen, den Quelltext ausgeben, Haltepunkte setzen, die Ausführung verfolgen und Informationen über verschiedene Teile Ihres Skripts während seiner Ausführung einholen.
Mit dem Debugger gibt es nur wenige Probleme, die Ihnen verborgen bleiben. Es
lassen sich Probleme damit schneller feststellen als mit print
-Anweisungen.
Frage:
Ich verwende emacs. Gibt es eine Möglichkeit, den Perl-Debugger zusammen mit
emacs zu verwenden?
Antwort:
Aber klar. In der Datei cperl-mode.el finden Sie massenweise Material
darüber, wie man Perl in den emacs einbindet. Diese Datei gehört zum
Standardumfang von Perl und befindet sich in dem Verzeichnis emacs.
Frage:
Ich bin eher an Debugger mit grafischer Oberfläche gewöhnt. All diese Befehle
auf Befehlszeilenebene nerven mich. Gibt es für Perl auch visuelle Debugger?
Antwort:
Wenn Sie den ActiveState-Port von Perl für Windows verwenden, steht Ihnen
über ActiveState ein phantastischer visueller Perl-Debugger zur Verfügung.
Weitere Informationen finden Sie unter http://www.activestate.com
.
Der Workshop enthält Quizfragen, die Ihnen helfen sollen, Ihr Wissen zu festigen, und Übungen, die Sie anregen sollen, das eben Gelernte umzusetzen und eigene Erfahrungen zu sammeln. Versuchen Sie, das Quiz und die Übungen zu beantworten und zu verstehen, bevor Sie zur Lektion des nächsten Tages übergehen.
-w
oder
print
?
X
und V
zum Ausgeben der Variablen?
Geben Sie folgendes Skript ein:
#!/usr/bin/perl -w
my @foo = (2,5,3,7,4,3,4,3,2,3,9);
foreach $wert (0..10) {
&multiplizieren($wert, $foo[$wert]);
}
sub multiplizieren {
my ($num, $val) = @_;
print "$num mal $val ist gleich ", $num * $val, "\n";
}
Lassen Sie den Debugger darüber laufen und führen Sie folgende Debugger- Operationen durch:
t
die Verfolgung ein, und lassen Sie mit c
die Ergebnisse
anzeigen.
R
ein, um das Skript erneut auszuführen. Gehen Sie mit n
schrittweise
durch das Skript. Wenn Sie sich innerhalb der foreach
-Schleife befinden, lassen
Sie die Werte für $wert
mehrmals ausgeben.
R
ein, um das Skript erneut auszuführen. Gehen Sie mit s
schrittweise
durch das Skript. Geben Sie innerhalb der Subroutine &multiplizieren()
die
Werte von $num
und $val
aus. Kehren Sie mit r
wieder aus der Subroutine
&multiplizieren()
zurück.
R
ein, um das Skript erneut auszuführen. Setzen Sie mit dem Befehl b
in der Subroutine &multiplizieren()
einen Haltepunkt. Lassen Sie den
Haltepunkt mit L
anzeigen. Führen Sie mit c
das Programm bis zum Haltepunkt
aus. Löschen Sie mit d
den Haltepunkt wieder.
#!/usr/bin/perl -w
@foo = (2,5,3,7,4,3,4,3,2,9);
while ($i < $#foo) {
&multiplizieren($i, $foo[$i]);
}
sub multiplizieren {
my ($num, $val) = @_;
print "$num mal $val ist gleich ", $num * $val, "\n";
}
Hier die Antworten auf die Workshop-Fragen aus dem vorigen Abschnitt.
-w
dient dazu, Syntaxfehler oder schlechten Programmierstil zu finden
(oder zu vermeiden). Der Perl-Debugger unterstützt Sie bei allen anderen
Problemen: wenn Arrays nicht eingerichtet oder ausgegeben werden, Werte nicht
übereinstimmen oder die Ausführung des Skripts nicht der erstrebten Logik
entspricht. Die gleiche Hilfestellung - allerdings in reduzierter Form - erhalten Sie
mit der print
-Anweisung, die jedoch mit mehr Aufwand verbunden ist und oft
größere Schwierigkeiten hat, das Problem zu orten. Mit dem Debugger können
Sie auch die Werte von Variablen ändern und beliebige Codefragmente
ausführen, während das Skript gerade in Ausführung ist - all dies ist mit einer
einfachen print
-Anweisung nicht möglich.
perl
ein, gefolgt
von der Option -d
, dem Namen Ihres Skripts und etwaiger Skriptargumente.
Wenn Sie mit MacPerl arbeiten, müssen Sie den Perl-Debugger über das Menü
Script aufrufen.
l
allein zeigt die nachfolgenden Codezeilen an
l
zusammen mit einer Zeilennummer zeigt genau diese Zeile an
l
zusammen mit einem Zeilenbereich zeigt genau diesen Bereich an
-
bringt eine Reihe von voranstehenden Codezeilen zur Anzeige
w
zeigt einige Zeilen vor und einige Zeilen nach der aktuellen Zeile an
X
gefolgt vom Variablennamen (ohne die Zeichen $
, @
oder %
) aus. Andere
Variablen und die Ergebnisse von Perl-Ausdrücken (wie zum Beispiel
$hash{'key'}
) geben Sie mit dem Befehl x
aus.
n
verwenden, überspringen Sie die Subroutinen. Diese werden zwar ausgeführt,
aber ihr Inhalt wird nicht angezeigt.
X
gibt die Variablen für das aktuelle Paket (main
) aus. Der Befehl V
gibt
Variablen in einem beliebigen gegebenen Paket aus (wenn Sie später mit Paketen
arbeiten, wird Ihnen dieser Befehl noch sehr dienlich sein).
$i
wurde nicht initialisiert, so dass die Subroutine &multiplizieren()
Initialisierungsfehler auslöst, wenn sie versucht, den Wert von $num
auszugeben.
$i
wird nicht inkrementiert. Das bedeutet, dass i
immer den Wert 0
behält
und in einer Endlosschleife hängenbleibt.